Summary
This tutorial demonstrates how to access AppEEARS Cloud Optimized GeoTIFF (COG) outputs. NASA's Application for Extracting and Exploring Analysis Ready Samples (AρρEEARS) has been migrated to NASA's Earthdata Cloud space located in AWS us-west 2. This enables the user working in the cloud instance deployed in AWS us-west 2 to access outputs direcly in the cloud using S3 link returned in the location header of the response. In this tutorial, we will walk through the process of submitting an area sample and accessing a Cloud Optimized GeoTIFF (COG) outputs from AppEEARS. The Dixie Fire, the second-largest fire in California history is used as an example in this tutorial. According to CalFire, the fire has started on July 13, 2021 and burned more than 963,276 acres. On August 18, the Dixie Fire merged with the Morgan Fire, which had been started by lightning August 12, close to Lassen National Park. The fire was one hundred percent contained by October 2021.
Requirements
Learning Objectives
Tutorial Outline
Import the required packages.
import requests
import getpass, pprint, time, os, cgi, json
import geopandas
import numpy
import datetime
import os
import io
import json
from urllib import parse
import requests
from netrc import netrc
from uuid import uuid4
import time
from pathlib import Path
from datetime import datetime, timezone
from botocore.client import Config
import rioxarray
import xarray
import hvplot.xarray
import holoviews
import geoviews
import rasterio
from rasterio.plot import show
from rasterio.session import AWSSession
import s3fs
import pandas
import warnings
import sys
sys.path.append('../modules/')
import aws_session
warnings.filterwarnings('ignore')
In order to successfully run this tutorial, it is required to create a .netrc file in your home directory. The function _validate_netrc defined in aws_session checks if the netrc file with proper format exists in your home directory. If the netrc file does not exist, it will prompt to ask your Earthdata Login username and password and will create a netrc file. Please see the Prerequisites section in README.md.
# validate if netrc file is present else create one via the user / password prompt for the urs.earthdata.nasa.gov
aws_session._validate_netrc()
INFO : netrc file is setup for urs.earthdata.nasa.gov already ...
In this step, we are going to submit an area request with GeoTIFF as an output format. You can also submit this request using AppEEARS Graphic User Interface (GUI) and upload the JSON file provided in the repository (AppEEARS-Data-Resources/additional_file/Dixie-Fire-request.json). If you have your completed request, save your task_id to a variable, skip this step, and move to the next step of tutorial.
Assign the AρρEEARS API endpoint to a variable.
appeears_API_endpoint = 'https://appeears.earthdatacloud.nasa.gov/api/'
To access AppEEARS API a token is needed. This token is created using AppEEARS API endpoint, Earthdata Login credential stored in .netrc file, and requests.post function. This generated token will be added to the header. The header will be passed to requests.post function showing you are a qualifid user for submit and access a request.
urs = 'urs.earthdata.nasa.gov'
token_response = requests.post('{}login'.format(appeears_API_endpoint), auth = (netrc().authenticators(urs)[0],netrc().authenticators(urs)[2])).json() # Insert API URL, call login service, provide credentials & return json
token = token_response['token'] # Save login token to a variable
head = {'Authorization': 'Bearer {}'.format(token)} # Create a header to store token information, needed to submit a request
Next, compile a JSON object with the request parameters. Dixie fire, started on July 13, 2021, but we extended the search query to two years to see the time series. The GeoJSON of Region of Interest(ROI) including Lassen National Park region, CA can be downloaded from the repository. For this tutorial, we are requesting _500m_16_days_EVI layer of MOD13A1.061 to see how Enhanced Vegetation Indices (EVI) varies before and after the fire event. Learn more about the MODIS Vegetation Indices 16-Day Version 6.1 product here. Below the AppEEARS search parameters are defined and the task JSON .
task_name = "Dixie Fire"
task_type = 'area' # Type of task, area or point
proj = 'geographic' # Set output projection
outFormat = 'geotiff' # Set output file format type
startDate = '01-01-2021' # Start of the date range for which to extract data: MM-DD-YYYY
endDate = '12-31-2022' # End of the date range for which to extract data: MM-DD-YYYY
ROI = geopandas.read_file('../additional_files/DixieFire.geojson').to_json()
prodLayer = [{'layer': '_500m_16_days_EVI', 'product': 'MOD13A1.061'}]
task = {
'task_type': task_type,
'task_name': task_name,
'params': {
'dates': [
{
'startDate': startDate,
'endDate': endDate
}],
'layers': prodLayer,
'output': {
'format': {
'type': outFormat},
'projection': proj},
'geo': json.loads(ROI),
}
}
Next, submit the AppEEARS request using post function from requests library.
task_response = requests.post('{}task'.format(appeears_API_endpoint), json=task, headers=head).json() # Post json to the API task service, return response as json
task_response # Print task response
{'task_id': 'a76dc9ab-867f-4cd0-bc26-a5eb7b54820e', 'status': 'pending'}
Save the task_id and wait until your request is processed and complete.
task_id = task_response['task_id']
task_id
'a76dc9ab-867f-4cd0-bc26-a5eb7b54820e'
# Ping API until request is complete, then continue to Section 3
while requests.get('{}task/{}'.format(appeears_API_endpoint, task_id), headers=head).json()['status'] != 'done':
print(requests.get('{}task/{}'.format(appeears_API_endpoint, task_id), headers=head).json()['status'])
time.sleep(60)
print(requests.get('{}task/{}'.format(appeears_API_endpoint, task_id), headers=head).json()['status'])
queued queued processing processing done
Now that we have our outputs ready, we can get the bundle information for the files included in the outputs. If you submitted your request using AppEEARS GUI, assign your sample's task_id to the variable task_id below.
# task_id = 'a1714bef-bb86-4bd3-be54-bb84c01a11d8'
requests.get is used toget the bundle information. Below, bundle information for the first output file is printed. The bundle information includes s3_url in addition to the other information such as file_name, file_id, and file_type.
Each output file can be downloaded using the file_id and AppEEARS API endpoint. AppEEARS outputs are stored in an AWS bucket that can be accessed using S3_url.
bundle = requests.get('{}bundle/{}'.format(appeears_API_endpoint,task_id), headers=head).json() # Call API and return bundle contents for the task_id as json
bundle['files'][0]
{'sha256': 'ff02801f5d242355793a4942e705a07494d08c4671c19f6113f730e75d145fe3',
'file_id': 'd44891bd-add8-415d-8092-0d7222e54b26',
'file_name': 'MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2020353_aid0001.tif',
'file_size': 341889,
'file_type': 'tif',
's3_url': 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2020353_aid0001.tif'}
Below, the S3 Links to Cloud Optimized GeoTIFF outputs and then S3 links for EVI layers are filted.
cog_urls = [f['s3_url'] for f in bundle['files'] if f['file_type'] == 'tif']
# cog_urls
EVI_cog_urls = [link for link in cog_urls if '500m_16_days_EVI' in link]
EVI_cog_urls
['s3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2020353_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021001_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021017_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021033_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021049_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021065_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021081_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021097_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021113_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021129_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021145_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021161_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021177_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021193_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021209_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021225_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021241_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021257_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021273_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021289_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021305_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021321_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021337_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2021353_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022001_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022017_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022033_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022049_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022065_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022081_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022097_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022113_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022129_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022145_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022161_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022177_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022193_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022209_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022225_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022241_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022257_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022273_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022289_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022305_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022321_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022337_aid0001.tif', 's3://appeears-output/a76dc9ab-867f-4cd0-bc26-a5eb7b54820e/MOD13A1.061_2020352_to_2022365/MOD13A1.061__500m_16_days_EVI_doy2022353_aid0001.tif']
In the same way, get the links to quality layers.
qual_cog_urls = [link for link in cog_urls if '500m_16_days_VI_Quality' in link]
AppEEARS outputs are freely accessible from a cloud instance in us-west-2 region. In order to access our output files, a Boto3 session is needed. The Boto session stores the required configurations for an easy integration between Python and AWS services. Below, get_boto3_refreshable_session stored in aws_session will access your Earthdata login credentidals store in .netrc file and generate S3 credential by making a call to AppEEARS S3 credential endpoint, and create a boto3 session. This session will be auto-renewed as needed to prevent timeouts errors related to S3 credentials.
region_name = 'us-west-2'
s3_creds_endpoint = f"{appeears_API_endpoint}/s3credentials"
# Boto3 Session required by the rioxarray package
boto3_session = aws_session.get_boto3_refreshable_session(s3_creds_endpoint, region_name)
INFO : Getting new temporary credentials from AppEEARS API https://appeears.earthdatacloud.nasa.gov/api//s3credentials...
Below, GDAL and AWS configuration and any environmner options are passed to
rasterio.env(). When the Python context manager is entered all the configuration options are set and when the context is exited, configuration options are removed.
rio_env = rasterio.Env(
AWSSession(boto3_session),
GDAL_DISABLE_READDIR_ON_OPEN='EMPTY_DIR',
GDAL_HTTP_COOKIEFILE=os.path.expanduser('~/cookies.txt'),
GDAL_HTTP_COOKIEJAR=os.path.expanduser('~/cookies.txt')
)
rio_env.__enter__()
<rasterio.env.Env at 0x7fa552504910>
COG datasets can be read using open_rasterio function from rioxarray library. The coordinates are generated automatically from the file’s geoinformation.
Below, the first EVI S3 link is read as a xarray.DataArray. The data array is scaled and nodata values are masked by setting mask_and_scale to True. Chunk sizes can be provided or can be set to 'auto' to make a sensible chunk sized according to each dimension.
EVI_obj = rioxarray.open_rasterio(EVI_cog_urls[0], chunks = 'auto' , mask_and_scale = True).squeeze('band', drop=True)
EVI_obj
<xarray.DataArray (y: 412, x: 399)>
dask.array<getitem, shape=(412, 399), dtype=float32, chunksize=(412, 399), chunktype=numpy.ndarray>
Coordinates:
* x (x) float64 -121.8 -121.8 -121.8 ... -120.1 -120.1 -120.1
* y (y) float64 41.21 41.21 41.2 41.2 ... 39.51 39.51 39.5 39.5
spatial_ref int64 0
Attributes:
AREA_OR_POINT: Area
units: NAIf the chunk shape and array are the same, the chunk selected for the dataset is bigger in size. you can set the chunk size manually.
EVI_obj.chunk(chunks={"x": 5, "y": 5})
<xarray.DataArray (y: 412, x: 399)>
dask.array<rechunk-merge, shape=(412, 399), dtype=float32, chunksize=(5, 5), chunktype=numpy.ndarray>
Coordinates:
* x (x) float64 -121.8 -121.8 -121.8 ... -120.1 -120.1 -120.1
* y (y) float64 41.21 41.21 41.2 41.2 ... 39.51 39.51 39.5 39.5
spatial_ref int64 0
Attributes:
AREA_OR_POINT: Area
units: NATo view the values in the data array, you can use load function.
EVI_obj.load()
<xarray.DataArray (y: 412, x: 399)>
array([[ 0.4951 , 0.5316 , 0.5316 , ..., 0.0829 ,
0.0829 , 0.0339 ],
[ 0.4951 , 0.4951 , 0.5316 , ..., 0.1221 ,
0.1343 , 0.1433 ],
[ 0.4894 , 0.3274 , 0.3274 , ..., 0.1858 ,
0.1646 , 0.1646 ],
...,
[ nan, -0.0211 , -0.0211 , ..., 0.2356 ,
0.1786 , 0.0675 ],
[ 0.0751 , -0.0254 , -0.0211 , ..., 0.1785 ,
0.2066 , 0.1476 ],
[ 0.017 , -0.0402 , nan, ..., 0.1785 ,
0.1785 , 0.21519999]], dtype=float32)
Coordinates:
* x (x) float64 -121.8 -121.8 -121.8 ... -120.1 -120.1 -120.1
* y (y) float64 41.21 41.21 41.2 41.2 ... 39.51 39.51 39.5 39.5
spatial_ref int64 0
Attributes:
AREA_OR_POINT: Area
units: NANow the data are loaded, lets quickly visualize the first EVI file using hvplot.image function.
EVI_obj.hvplot.image(x='x', y='y', rasterize=True, title= EVI_cog_urls[0].split('/')[-1], colorbar=True, cmap='YlGnBu').opts(clim=(0, 0.8))
Next, lets access the EVI time series. Here, the EVI time series is being read and concadenated to a single xarray.DataArray using the concat function.
To do this, we first build a list of times from the S3 URLs and convert that to an xarray variable.
time_list = []
for obs in range(len(EVI_cog_urls)):
doy = EVI_cog_urls[obs].split('_doy')[1].split('_aid')[0]
doy_date = datetime.strptime(doy, '%Y%j').strftime('%d-%m-%Y')
time_list.append(doy_date)
time = xarray.Variable('time', time_list)
chunks=dict(band=1, x=100, y=100)
EVI_series = xarray.concat([rioxarray.open_rasterio(f, chunks = 'auto', mask_and_scale = True).squeeze('band', drop=True) for f in EVI_cog_urls], dim=time)
EVI_series = EVI_series.rename('EVI')
EVI_series
<xarray.DataArray 'EVI' (time: 47, y: 412, x: 399)>
dask.array<concatenate, shape=(47, 412, 399), dtype=float32, chunksize=(1, 412, 399), chunktype=numpy.ndarray>
Coordinates:
* x (x) float64 -121.8 -121.8 -121.8 ... -120.1 -120.1 -120.1
* y (y) float64 41.21 41.21 41.2 41.2 ... 39.51 39.51 39.5 39.5
spatial_ref int64 0
* time (time) <U10 '18-12-2020' '01-01-2021' ... '19-12-2022'
Attributes:
AREA_OR_POINT: Area
units: NABelow, a dynamic plot is created to visually look at the variation in EVI through out these two years. You can manually select the dates from the dropdown next to the map. The latest observation before the fire event is on July 12, 2021. and the next observation is on July 28, 2021 which is the first observation after the fire event. A sudden decrease in EVI after July 12, 2021 is visually noticable and the area that vegetation is being removed grows spatially as you look through next observations. If you look at the observattions of the next year, you still can identify the scar left by fire.
map = EVI_series.hvplot.image(x='x', y='y',groupby='time', rasterize=True, colorbar=True, frame_width= 800, frame_height= 500, cmap='YlGnBu').opts(clim=(0, 0.8))
map
You can also create a plot showing the EVI time series for a specific latittude and longitude.
EVI_series.sel(x=-121.260, y=40.330,method='nearest').hvplot.line(x='time', y='EVI', rot=90, frame_width= 1000, frame_height= 300, fontscale=1.5)
Now, combine the time series map and the plot. Below,a dynamic map is created that shows the EVI time series as you move your mouse to a different location on the map. You can update the base map by selecting the date from the dropdown menu on the far right side. This is an easy way to explore your data before further processing.
# Stream of X and Y positional data
posxy = holoviews.streams.PointerXY(source=map, x=-121.4, y=40.03)
# Function to build a time series using the mouse hover positional information retrieved from the map
def point_spectra(x,y):
return EVI_series.sel(x=x,y=y,method='nearest').hvplot.line(x='time', y='EVI', rot=90, frame_width= 800, frame_height= 500, fontscale=1.5)
# Define the Dynamic Maps
point_dmap = holoviews.DynamicMap(point_spectra, streams=[posxy])
# Plot the Map and Dynamic Map side by side
map + point_dmap
Finally, exit the context manager to remove the configuration options.
# Exit our context
rio_env.__exit__()
Email: LPDAAC@usgs.gov
Voice: +1-866-573-3222
Organization: Land Processes Distributed Active Archive Center (LP DAAC)¹
Website: https://lpdaac.usgs.gov/
Date last modified: 02-16-2022
¹Work performed under USGS contract G15PD00467 for NASA contract NNG14HH33I.